﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Ssdb.Provider
{
    /// <summary>
    ///     Class SsdbClient.
    /// </summary>
    public class BaseSsdbClient
    {
        /// <summary>
        ///     The socket
        /// </summary>
        private readonly SsdbSocket socket;

        /// <summary>
        ///     The resp code
        /// </summary>
        private string respCode;

        /// <summary>
        ///     Initializes a new instance of the <see cref="BaseSsdbClient" /> class.
        /// </summary>
        public BaseSsdbClient()
        {
            this.socket = new SsdbSocket();
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="BaseSsdbClient" /> class.
        /// </summary>
        /// <param name="hostName">Name of the host.</param>
        /// <param name="port">The port.</param>
        public BaseSsdbClient(string hostName, int port)
        {
            this.socket = new SsdbSocket(hostName, port);
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="BaseSsdbClient" /> class.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        public BaseSsdbClient(string connectionString = "SsdbConnectiongString")
        {
            this.socket = new SsdbSocket(connectionString);
        }

        /// <summary>
        ///     Finalizes an instance of the <see cref="BaseSsdbClient" /> class.
        /// </summary>
        ~BaseSsdbClient()
        {
            this.Close();
        }

        /// <summary>
        ///     Deletes the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        public void Del(byte[] key)
        {
            List<byte[]> resp = this.Request("del", key);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Deletes the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        public void Del(string key)
        {
            this.Del(this._Bytes(key));
        }

        /// <summary>
        ///     Existses the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Exists(byte[] key)
        {
            List<byte[]> resp = this.Request("exists", key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return (this._String(resp[1]) == "1");
        }

        /// <summary>
        ///     Existses the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Exists(string key)
        {
            return this.Exists(this._Bytes(key));
        }

        /// <summary>
        ///     Existses the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Exists(byte[] name, byte[] key)
        {
            List<byte[]> resp = this.Request("zexists", name, key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return (this._String(resp[1]) == "1");
        }

        /// <summary>
        ///     Gets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns>returns true if name.key is found, otherwise returns false.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Get(byte[] key, out byte[] val)
        {
            val = null;
            List<byte[]> resp = this.Request("get", key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            val = resp[1];
            return true;
        }

        /// <summary>
        ///     Gets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Get(string key, out string val)
        {
            val = null;
            byte[] bs;
            if (!this.Get(key, out bs))
            {
                return false;
            }
            val = this._String(bs);
            return true;
        }

        /// <summary>
        ///     Hdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        public void Hdel(byte[] name, byte[] key)
        {
            List<byte[]> resp = this.Request("hdel", name, key);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Hdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        public void Hdel(string name, string key)
        {
            this.Hdel(this._Bytes(name), this._Bytes(key));
        }

        /// <summary>
        ///     Hexistses the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Hexists(byte[] name, byte[] key)
        {
            List<byte[]> resp = this.Request("hexists", name, key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return (this._String(resp[1]) == "1");
        }

        /// <summary>
        ///     Hexistses the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Hexists(string name, string key)
        {
            return this.Hexists(this._Bytes(name), this._Bytes(key));
        }

        /// <summary>
        ///     Hgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns>returns true if name.key is found, otherwise returns false.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Hget(byte[] name, byte[] key, out byte[] val)
        {
            val = null;
            List<byte[]> resp = this.Request("hget", name, key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            val = resp[1];
            return true;
        }

        /// <summary>
        ///     Hgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Hget(string name, string key, out byte[] val)
        {
            return this.Hget(this._Bytes(name), this._Bytes(key), out val);
        }

        /// <summary>
        ///     Hgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Hget(string name, string key, out string val)
        {
            val = null;
            byte[] bs;
            if (!this.Hget(name, key, out bs))
            {
                return false;
            }
            val = this._String(bs);
            return true;
        }

        /// <summary>
        ///     Hrscans the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keyStart">The key start.</param>
        /// <param name="keyEnd">The key end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Hrscan(string name, string keyStart, string keyEnd, long limit)
        {
            List<byte[]> resp = this.Request("hrscan", name, keyStart, keyEnd, limit.ToString());
            return this.Parse_scan_resp(resp);
        }

        /// <summary>
        ///     Hscans the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keyStart">The key start.</param>
        /// <param name="keyEnd">The key end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Hscan(string name, string keyStart, string keyEnd, long limit)
        {
            List<byte[]> resp = this.Request("hscan", name, keyStart, keyEnd, limit.ToString());
            return this.Parse_scan_resp(resp);
        }

        /// <summary>
        ///     Hsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        public void Hset(byte[] name, byte[] key, byte[] val)
        {
            List<byte[]> resp = this.Request("hset", name, key, val);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Hsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        public void Hset(string name, string key, byte[] val)
        {
            this.Hset(this._Bytes(name), this._Bytes(key), val);
        }

        /// <summary>
        ///     Hsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        public void Hset(string name, string key, string val)
        {
            this.Hset(this._Bytes(name), this._Bytes(key), this._Bytes(val));
        }

        /// <summary>
        ///     Hsizes the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>System.Int64.</returns>
        public long Hsize(string name)
        {
            return this.Hsize(this._Bytes(name));
        }

        /// <summary>
        ///     Hsizes the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>System.Int64.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public long Hsize(byte[] name)
        {
            List<byte[]> resp = this.Request("hsize", name);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return long.Parse(this._String(resp[1]));
        }

        /// <summary>
        ///     Multi_hdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        public void Multi_hdel(byte[] name, byte[][] keys)
        {
            byte[][] req = new byte[keys.Length + 1][];
            req[0] = name;
            for (int i = 0; i < keys.Length; i++)
            {
                req[i + 1] = keys[i];
            }
            List<byte[]> resp = this.Request("multi_hdel", req);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Multi_hdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        public void Multi_hdel(string name, string[] keys)
        {
            byte[][] req = new byte[keys.Length][];
            for (int i = 0; i < keys.Length; i++)
            {
                req[i] = this._Bytes(keys[i]);
            }
            this.Multi_hdel(this._Bytes(name), req);
        }

        /// <summary>
        ///     Multi_hgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Multi_hget(byte[] name, byte[][] keys)
        {
            byte[][] req = new byte[keys.Length + 1][];
            req[0] = name;
            for (int i = 0; i < keys.Length; i++)
            {
                req[i + 1] = keys[i];
            }
            List<byte[]> resp = this.Request("multi_hget", req);
            KeyValuePair<string, byte[]>[] ret = this.Parse_scan_resp(resp);

            return ret;
        }

        /// <summary>
        ///     Multi_hgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Multi_hget(string name, string[] keys)
        {
            byte[][] req = new byte[keys.Length][];
            for (int i = 0; i < keys.Length; i++)
            {
                req[i] = this._Bytes(keys[i]);
            }
            return this.Multi_hget(this._Bytes(name), req);
        }

        /// <summary>
        ///     Multi_hsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="kvs">The KVS.</param>
        public void Multi_hset(byte[] name, KeyValuePair<byte[], byte[]>[] kvs)
        {
            byte[][] req = new byte[(kvs.Length * 2) + 1][];
            req[0] = name;
            for (int i = 0; i < kvs.Length; i++)
            {
                req[(2 * i) + 1] = kvs[i].Key;
                req[(2 * i) + 2] = kvs[i].Value;
            }
            List<byte[]> resp = this.Request("multi_hset", req);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Multi_hsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="kvs">The KVS.</param>
        public void Multi_hset(string name, KeyValuePair<string, string>[] kvs)
        {
            KeyValuePair<byte[], byte[]>[] req = new KeyValuePair<byte[], byte[]>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                req[i] = new KeyValuePair<byte[], byte[]>(this._Bytes(kvs[i].Key), this._Bytes(kvs[i].Value));
            }
            this.Multi_hset(this._Bytes(name), req);
        }

        /// <summary>
        ///     Multi_zdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        public void Multi_zdel(byte[] name, byte[][] keys)
        {
            byte[][] req = new byte[keys.Length + 1][];
            req[0] = name;
            for (int i = 0; i < keys.Length; i++)
            {
                req[i + 1] = keys[i];
            }
            List<byte[]> resp = this.Request("multi_zdel", req);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Multi_zdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        public void Multi_zdel(string name, string[] keys)
        {
            byte[][] req = new byte[keys.Length][];
            for (int i = 0; i < keys.Length; i++)
            {
                req[i] = this._Bytes(keys[i]);
            }
            this.Multi_zdel(this._Bytes(name), req);
        }

        /// <summary>
        ///     Multi_zgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Multi_zget(byte[] name, byte[][] keys)
        {
            byte[][] req = new byte[keys.Length + 1][];
            req[0] = name;
            for (int i = 0; i < keys.Length; i++)
            {
                req[i + 1] = keys[i];
            }
            List<byte[]> resp = this.Request("multi_zget", req);
            KeyValuePair<string, byte[]>[] kvs = this.Parse_scan_resp(resp);
            KeyValuePair<string, long>[] ret = new KeyValuePair<string, long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                string key = kvs[i].Key;
                long score = long.Parse(this._String(kvs[i].Value));
                ret[i] = new KeyValuePair<string, long>(key, score);
            }
            return ret;
        }

        /// <summary>
        ///     Multi_zgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keys">The keys.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Multi_zget(string name, string[] keys)
        {
            byte[][] req = new byte[keys.Length][];
            for (int i = 0; i < keys.Length; i++)
            {
                req[i] = this._Bytes(keys[i]);
            }
            return this.Multi_zget(this._Bytes(name), req);
        }

        /// <summary>
        ///     Multi_zsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="kvs">The KVS.</param>
        public void Multi_zset(byte[] name, KeyValuePair<byte[], long>[] kvs)
        {
            byte[][] req = new byte[(kvs.Length * 2) + 1][];
            req[0] = name;
            for (int i = 0; i < kvs.Length; i++)
            {
                req[(2 * i) + 1] = kvs[i].Key;
                req[(2 * i) + 2] = this._Bytes(kvs[i].Value.ToString());
            }
            List<byte[]> resp = this.Request("multi_zset", req);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Multi_zsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="kvs">The KVS.</param>
        public void Multi_zset(string name, KeyValuePair<string, long>[] kvs)
        {
            KeyValuePair<byte[], long>[] req = new KeyValuePair<byte[], long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                req[i] = new KeyValuePair<byte[], long>(this._Bytes(kvs[i].Key), kvs[i].Value);
            }
            this.Multi_zset(this._Bytes(name), req);
        }

        /// <summary>
        ///     Requests the specified command.
        /// </summary>
        /// <param name="cmd">The command.</param>
        /// <param name="args">The arguments.</param>
        /// <returns>List&lt;System.Byte[]&gt;.</returns>
        public List<byte[]> Request(string cmd, params byte[][] args)
        {
            return this.socket.Request(cmd, args);
        }

        /// <summary>
        ///     Requests the specified req.
        /// </summary>
        /// <param name="req">The req.</param>
        /// <returns>List&lt;System.Byte[]&gt;.</returns>
        public List<byte[]> Request(List<byte[]> req)
        {
            return this.socket.Request(req);
        }

        /// <summary>
        ///     Requests the specified command.
        /// </summary>
        /// <param name="cmd">The command.</param>
        /// <param name="args">The arguments.</param>
        /// <returns>List&lt;System.Byte[]&gt;.</returns>
        public List<byte[]> Request(string cmd, params string[] args)
        {
            return this.socket.Request(cmd, args);
        }

        /// <summary>
        ///     Rscans the specified key start.
        /// </summary>
        /// <param name="keyStart">The key start.</param>
        /// <param name="keyEnd">The key end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Rscan(string keyStart, string keyEnd, long limit)
        {
            List<byte[]> resp = this.Request("rscan", keyStart, keyEnd, limit.ToString());
            return this.Parse_scan_resp(resp);
        }

        /// <summary>
        ///     Scans the specified key start.
        /// </summary>
        /// <param name="keyStart">The key start.</param>
        /// <param name="keyEnd">The key end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        public KeyValuePair<string, byte[]>[] Scan(string keyStart, string keyEnd, long limit)
        {
            List<byte[]> resp = this.Request("scan", keyStart, keyEnd, limit.ToString());
            return this.Parse_scan_resp(resp);
        }

        /// <summary>
        ///     Sets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        public bool Set(string key, string val)
        {
            return this.Set(this._Bytes(key), this._Bytes(val));
        }

        /// <summary>
        ///     Zdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        public void Zdel(byte[] name, byte[] key)
        {
            List<byte[]> resp = this.Request("zdel", name, key);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Zdels the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        public void Zdel(string name, string key)
        {
            this.Zdel(this._Bytes(name), this._Bytes(key));
        }

        /// <summary>
        ///     Zexistses the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Zexists(byte[] name, byte[] key)
        {
            List<byte[]> resp = this.Request("zexists", name, key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return (this._String(resp[1]) == "1");
        }

        /// <summary>
        ///     Zexistses the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Zexists(string name, string key)
        {
            return this.Zexists(this._Bytes(name), this._Bytes(key));
        }

        /// <summary>
        ///     Zgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="score">The score.</param>
        /// <returns>returns true if name.key is found, otherwise returns false.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public bool Zget(byte[] name, byte[] key, out long score)
        {
            score = -1;
            List<byte[]> resp = this.Request("zget", name, key);
            this.respCode = this._String(resp[0]);
            if (this.respCode == "not_found")
            {
                return false;
            }
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            score = long.Parse(this._String(resp[1]));
            return true;
        }

        /// <summary>
        ///     Zgets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="score">The score.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool Zget(string name, string key, out long score)
        {
            return this.Zget(this._Bytes(name), this._Bytes(key), out score);
        }

        /// <summary>
        ///     Zincrs the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="increment">The increment.</param>
        /// <returns>System.Int64.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public long Zincr(byte[] name, byte[] key, long increment)
        {
            List<byte[]> resp = this.Request("zincr", name, key, this._Bytes(increment.ToString()));
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return long.Parse(this._String(resp[1]));
        }

        /// <summary>
        ///     Zincrs the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="increment">The increment.</param>
        /// <returns>System.Int64.</returns>
        public long Zincr(string name, string key, long increment)
        {
            return this.Zincr(this._Bytes(name), this._Bytes(key), increment);
        }

        /// <summary>
        ///     Zranges the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Zrange(string name, int offset, int limit)
        {
            List<byte[]> resp = this.Request("zrange", name, offset.ToString(), limit.ToString());
            KeyValuePair<string, byte[]>[] kvs = this.Parse_scan_resp(resp);
            KeyValuePair<string, long>[] ret = new KeyValuePair<string, long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                string key = kvs[i].Key;
                long score = long.Parse(this._String(kvs[i].Value));
                ret[i] = new KeyValuePair<string, long>(key, score);
            }
            return ret;
        }

        /// <summary>
        ///     Zrranges the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Zrrange(string name, int offset, int limit)
        {
            List<byte[]> resp = this.Request("zrrange", name, offset.ToString(), limit.ToString());
            KeyValuePair<string, byte[]>[] kvs = this.Parse_scan_resp(resp);
            KeyValuePair<string, long>[] ret = new KeyValuePair<string, long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                string key = kvs[i].Key;
                long score = long.Parse(this._String(kvs[i].Value));
                ret[i] = new KeyValuePair<string, long>(key, score);
            }
            return ret;
        }

        /// <summary>
        ///     Zrscans the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keyStart">The key start.</param>
        /// <param name="scoreStart">The score start.</param>
        /// <param name="scoreEnd">The score end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Zrscan(string name, string keyStart, long scoreStart, long scoreEnd, long limit)
        {
            string scoreS = "";
            string scoreE = "";
            if (scoreStart != long.MaxValue)
            {
                scoreS = scoreStart.ToString();
            }
            if (scoreEnd != long.MinValue)
            {
                scoreE = scoreEnd.ToString();
            }
            List<byte[]> resp = this.Request("zrscan", name, keyStart, scoreS, scoreE, limit.ToString());
            KeyValuePair<string, byte[]>[] kvs = this.Parse_scan_resp(resp);
            KeyValuePair<string, long>[] ret = new KeyValuePair<string, long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                string key = kvs[i].Key;
                long score = long.Parse(this._String(kvs[i].Value));
                ret[i] = new KeyValuePair<string, long>(key, score);
            }
            return ret;
        }

        /// <summary>
        ///     Zscans the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="keyStart">The key start.</param>
        /// <param name="scoreStart">The score start.</param>
        /// <param name="scoreEnd">The score end.</param>
        /// <param name="limit">The limit.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Int64&gt;[].</returns>
        public KeyValuePair<string, long>[] Zscan(string name, string keyStart, long scoreStart, long scoreEnd, long limit)
        {
            string scoreS = "";
            string scoreE = "";
            if (scoreStart != long.MinValue)
            {
                scoreS = scoreStart.ToString();
            }
            if (scoreEnd != long.MaxValue)
            {
                scoreE = scoreEnd.ToString();
            }
            List<byte[]> resp = this.Request("zscan", name, keyStart, scoreS, scoreE, limit.ToString());
            KeyValuePair<string, byte[]>[] kvs = this.Parse_scan_resp(resp);
            KeyValuePair<string, long>[] ret = new KeyValuePair<string, long>[kvs.Length];
            for (int i = 0; i < kvs.Length; i++)
            {
                string key = kvs[i].Key;
                long score = long.Parse(this._String(kvs[i].Value));
                ret[i] = new KeyValuePair<string, long>(key, score);
            }
            return ret;
        }

        /// <summary>
        ///     Zsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="score">The score.</param>
        public void Zset(byte[] name, byte[] key, long score)
        {
            List<byte[]> resp = this.Request("zset", name, key, this._Bytes(score.ToString()));
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
        }

        /// <summary>
        ///     Zsets the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="key">The key.</param>
        /// <param name="score">The score.</param>
        public void Zset(string name, string key, long score)
        {
            this.Zset(this._Bytes(name), this._Bytes(key), score);
        }

        /// <summary>
        ///     Zsizes the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>System.Int64.</returns>
        /// <exception cref="System.Exception">Bad response!</exception>
        public long Zsize(byte[] name)
        {
            List<byte[]> resp = this.Request("zsize", name);
            this.respCode = this._String(resp[0]);
            this.Assert_ok();
            if (resp.Count != 2)
            {
                throw new Exception("Bad response!");
            }
            return long.Parse(this._String(resp[1]));
        }

        /// <summary>
        ///     Zsizes the specified name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>System.Int64.</returns>
        public long Zsize(string name)
        {
            return this.Zsize(this._Bytes(name));
        }

        /// <summary>
        ///     _s the bytes.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns>System.Byte[].</returns>
        private byte[] _Bytes(string s)
        {
            return Encoding.Default.GetBytes(s);
        }

        /// <summary>
        ///     _s the string.
        /// </summary>
        /// <param name="bs">The bs.</param>
        /// <returns>System.String.</returns>
        private string _String(byte[] bs)
        {
            return Encoding.Default.GetString(bs);
        }

        /// <summary>
        ///     Assert_oks this instance.
        /// </summary>
        /// <exception cref="System.Exception"></exception>
        private bool Assert_ok()
        {
            if (this.respCode != "ok")
            {
                throw new Exception(this.respCode);
            }
            return true;
        }

        /// <summary>
        ///     Closes this instance.
        /// </summary>
        private void Close()
        {
            this.socket.Close();
        }

        /// <summary>
        ///     Gets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        private bool Get(string key, out byte[] val)
        {
            return this.Get(this._Bytes(key), out val);
        }

        /// <summary>
        ///     Parse_scan_resps the specified resp.
        /// </summary>
        /// <param name="resp">The resp.</param>
        /// <returns>KeyValuePair&lt;System.String, System.Byte[]&gt;[].</returns>
        private KeyValuePair<string, byte[]>[] Parse_scan_resp(List<byte[]> resp)
        {
            this.respCode = this._String(resp[0]);
            this.Assert_ok();

            int size = (resp.Count - 1) / 2;
            KeyValuePair<string, byte[]>[] kvs = new KeyValuePair<string, byte[]>[size];
            for (int i = 0; i < size; i += 1)
            {
                string key = this._String(resp[i * 2 + 1]);
                byte[] val = resp[i * 2 + 2];
                kvs[i] = new KeyValuePair<string, byte[]>(key, val);
            }
            return kvs;
        }

        /// <summary>
        ///     Sets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="val">The value.</param>
        private bool Set(byte[] key, byte[] val)
        {
            List<byte[]> resp = this.Request("set", key, val);
            this.respCode = this._String(resp[0]);
            return this.Assert_ok();
        }

        #region 获取一个ssdb客户端实例

        /// <summary>
        ///     Gets the client.
        /// </summary>
        /// <returns>SsdbClient.</returns>
        public static BaseSsdbClient GetBaseClient()
        {
            return new BaseSsdbClient();
        }

        /// <summary>
        ///     Gets the client.
        /// </summary>
        /// <param name="hostName">Name of the host.</param>
        /// <param name="port">The port.</param>
        /// <returns>SsdbClient.</returns>
        public static BaseSsdbClient GetBaseClient(string hostName, int port)
        {
            return new BaseSsdbClient(hostName, port);
        }

        /// <summary>
        ///     Gets the client.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <returns>SsdbClient.</returns>
        // ReSharper disable once MethodOverloadWithOptionalParameter
        public static BaseSsdbClient GetBaseClient(string connectionString = "SsdbConnectiongString")
        {
            return new BaseSsdbClient(connectionString);
        }

        #endregion 获取一个ssdb客户端实例
    }
}